﻿using System.Net.Sockets;

namespace ClassLibrary_fqy_NET.SocketHelper
{
    /// <summary>
    /// 此类创建一个大缓冲区，该缓冲区可以划分并分配给SocketAsyncEventArgs对象，用于每个套接字I/O操作。
    /// 这使得缓冲区可以很容易地重复使用，并防止堆内存碎片化。
    /// BufferManager类上公开的操作不是线程安全的。
    /// </summary>
    internal class BufferManager
    {
        private int m_numBytes;                 // 缓冲池控制的字节总数
        private byte[]? m_buffer;                // 缓冲区管理器维护的底层字节数组
        private Stack<int>? m_freeIndexPool;     //
        private int m_currentIndex;
        private int m_bufferSize;

        /// <summary>
        /// 初始化缓冲区
        /// </summary>
        /// <param name="totalBytes">缓冲池控制的字节总数</param>
        /// <param name="bufferSize">缓冲区管理器维护的底层字节数组总数</param>
        public BufferManager(int totalBytes, int bufferSize)
        {
            m_numBytes = totalBytes;
            m_currentIndex = 0;
            m_bufferSize = bufferSize;
            m_freeIndexPool = new Stack<int>();
        }
        /// <summary>
        /// 分配缓冲池使用的缓冲空间
        /// </summary>
        public void InitBuffer()
        {
            // 创建一个很大的缓冲区并分割SocketAsyncEventArg对象
            m_buffer = new byte[m_numBytes];
        }
        /// <summary>
        /// 将缓冲池中的缓冲区分配给指定的SocketAsyncEventArgs对象
        /// </summary>
        /// <param name="args"></param>
        /// <returns>如果缓冲区设置成功，则为true，否则为false</returns>
        public bool SetBuffer(SocketAsyncEventArgs args)
        {
            if (m_freeIndexPool!.Count > 0)
            {
                args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize);//设置要与异步套接字方法一起使用的数据缓冲区
            }
            else
            {
                if ((m_numBytes - m_bufferSize) < m_currentIndex)
                {
                    return false;
                }
                args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize);
                m_currentIndex += m_bufferSize;
            }
            return true;
        }
        /// <summary>
        /// 从SocketAsyncEventArg对象中删除缓冲区。这会将缓冲区释放回缓冲池
        /// </summary>
        /// <param name="args"></param>
        public void FreeBuffer(SocketAsyncEventArgs args)
        {
            m_freeIndexPool!.Push(args.Offset);
            args.SetBuffer(null, 0, 0);
        }


    }
}
